package com.mzlalal.mybatis.interceptor.mybatis;

import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.mzlalal.mybatis.interceptor.prop.MyBatisPlusProperties;
import com.mzlalal.mybatis.interceptor.util.TenantIdService;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;

/**
 * 对基础数据处理的抽象类
 * 子类必须实现processBaseField提供给父类使用处理
 * metaObject存在旧字段
 *
 * @author Mzlalal
 * @date 2021/5/17 19:33
 **/
@Slf4j
@Component
public abstract class BaseMetaObjectInterceptor implements MetaObjectHandler {
    /**
     * 拦截器配置
     */
    protected final MyBatisPlusProperties myBatisPlusProperties;

    /**
     * 租户获取工具类
     */
    protected final TenantIdService tenantIdService;

    @Autowired
    public BaseMetaObjectInterceptor(MyBatisPlusProperties myBatisPlusProperties, TenantIdService tenantIdService) {
        this.myBatisPlusProperties = myBatisPlusProperties;
        this.tenantIdService = tenantIdService;
    }

    @Override
    public void insertFill(MetaObject metaObject) {
        Map<String, Object> baseFieldMap = this.processBaseField();
        this.processInsertSql(metaObject, baseFieldMap);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        Map<String, Object> baseFieldMap = this.processBaseField();
        this.processUpdateSql(metaObject, baseFieldMap);
    }

    /**
     * 处理processBaseField,子类需要处理的
     * 基础字段赋值,需要每次都返回新的对象
     * 否则有线程安全的问题
     *
     * @return Map<String, Object> key需要填充的数据库列名,value需要填充的值
     */
    protected abstract Map<String, Object> processBaseField();

    /**
     * 处理新增INSERT语句时
     * 需要处理的基础数据
     *
     * @param metaObject   基础元对象(可以拿到当前的entity)
     * @param baseFieldMap 需要填充的字段
     */
    public void processInsertSql(MetaObject metaObject, Map<String, Object> baseFieldMap) {
        this.processBaseFields(metaObject, baseFieldMap, myBatisPlusProperties.getInsertBaseFields());
    }

    /**
     * 处理更新UPDATE语句时
     * 需要处理的基础数据
     *
     * @param metaObject   基础元对象(可以拿到当前的entity)
     * @param baseFieldMap 需要填充的字段
     */
    public void processUpdateSql(MetaObject metaObject, Map<String, Object> baseFieldMap) {
        this.processBaseFields(metaObject, baseFieldMap, myBatisPlusProperties.getUpdateBaseFields());
    }

    /**
     * @param metaObject              基础元对象(可以拿到当前的entity)
     * @param baseFieldMap            需要填充字段的值(MAP键值对形式)
     * @param currentProcessFieldList 当前需要处理的字段值(集合,在application.prop配置中的属性)
     */
    public void processBaseFields(MetaObject metaObject, Map<String, Object> baseFieldMap, List<String> currentProcessFieldList) {
        // 循环处理
        for (String item : currentProcessFieldList) {
            if (baseFieldMap.containsKey(item)) {
                // 获取当前处理字段的值
                Object fieldValue = baseFieldMap.get(item);
                Assert.notNull(fieldValue, "基础字段:" + fieldValue + "值不能为空");
                // 设置值 mybatis plus会判断hasSetter
                this.setFieldValByName(item, fieldValue, metaObject);
            }
        }
    }
}
